import { sendRequest } from '@/utils/api'
import { defineStore } from 'pinia'
import { shallowRef } from 'vue'
import type { RouteRecordRaw, RouteRecordRedirectOption } from 'vue-router'
import validator from 'validator'
import chalk from 'chalk'
import router from '@/router'
import { Layout } from '@/Layout'
import type { HttpResponse } from '@/utils/http'
import type { UserModel } from '@/api/user'
import type { RoleModel } from '@/api/role'
import type { MenuTreeModel } from '@/api/sysMenu'
import { MenuTypeCode, Platform } from '@/enums/system'
import { testRoutes, processRoutes } from '@/router/routes'
import defaultAvatar from '@/assets/images/default_avatar.png'

const buttonAuthMap = new Map<number, Set<string>>()
const setAuth = (pageId: number, auth: string) => {
  const list = buttonAuthMap.get(pageId)
  if (list) {
    list.add(auth)
  } else {
    buttonAuthMap.set(pageId, new Set([auth]))
  }
}

const generateRoutes = (
  routes: MenuTreeModel[],
  rootName?: string
): [RouteRecordRaw[], Sider[]] => {
  const turn: RouteRecordRaw[] = []
  const sider: Sider[] = []

  for (const route of routes) {
    const {
      children,
      menuName,
      routeUrl,
      menuTypeCode,
      id: _id,
      iconUrl,
      routeUrlDir,
      menuStatus
    } = route
    if (menuStatus === 0) continue

    const id = _id + '_name'
    const _isDir = menuTypeCode === MenuTypeCode.Dir
    if (_isDir) {
      if (hasChildren(children)) {
        const [t, s] = generateRoutes(children, rootName ? rootName : id)
        turn.push(...t)
        sider.push({
          name: id,
          label: menuName,
          children: s,
          isDir: _isDir,
          icon: iconUrl,
          isExternal: false
        })
      } else {
        sider.push({
          name: id,
          label: menuName,
          isDir: _isDir,
          icon: iconUrl,
          isExternal: false
        })
      }
      continue
    }

    const _route: RouteRecordRaw = {
      path: routeUrl!,
      name: id,
      component: null,
      children: null!,
      meta: {
        title: menuName,
        root: rootName,
        id: _id
      }
    }

    if (MenuTypeCode.BUTTON === menuTypeCode) {
      setAuth(route.parentMenuId, route.configuration)
    } else if (validator.isURL(routeUrl || '')) {
      sider.push({
        name: id,
        label: menuName,
        isDir: _isDir,
        href: routeUrl!,
        icon: iconUrl,
        isExternal: true
      })
    } else if (routeUrlDir) {
      _route.component = getView(routeUrlDir)
      turn.push(_route)
      sider.push({
        name: id,
        label: menuName,
        isDir: _isDir,
        icon: iconUrl,
        isExternal: false
      })
    }

    if (children) {
      const result = generateRoutes(children, rootName ? rootName : id)
      _route.children = result[0]
    }
  }

  return [turn, sider]
}

const hasChildren = (children: MenuTreeModel[]) => children && children.length

export const usePermissionStore = defineStore('permission', () => {
  const routes = shallowRef<RouteRecordRaw[]>([])
  const sider = shallowRef<Sider[]>([])
  const permissions = shallowRef<string[]>([])
  const userInfo = shallowRef<UserModel | null>(null)
  const buttonAuth = shallowRef<Map<number, Set<string>>>(new Map())
  const stagingFlag = shallowRef(false)
  const hrefRedirect = shallowRef('')
  const headSculpture = shallowRef('')

  const generate = async () => {
    await checkUserInfo()
    const [error, res] = await sendRequest<HttpResponse<RoleModel>>({
      module: 'user',
      api: 'permissionInfo',
      uri: {
        userId: userInfo.value?.id!
      }
    })
    if (error) throw error
    if (res.code !== 0) throw new Error(res.msg)
    stagingFlag.value = res.data.stagingFlag

    const menu = res.data.menuNodeList.find((e) => e.parentMenuTypeCode === Platform.PC)
    if (!menu) return

    buttonAuthMap.clear()
    const result = generateRoutes(menu.children)
    buttonAuth.value = buttonAuthMap
    routes.value = result[0]
    sider.value = result[1]

    if (__DEV__) {
      console.log(`${chalk.hex('#5352ed').bold('%s')}`, '路由', result[0])
      console.log(`${chalk.hex('#5352ed').bold('%s')}`, '侧边栏', result[1])
    }
  }

  const hasPermission = (auth: string[]) => {
    return auth.every((a) => permissions.value.includes(a))
  }

  const removeRoutes = () => {
    routes.value.forEach((e) => router.removeRoute(e.name!))
    routes.value = []
    permissions.value = []
    sider.value = []
  }

  const addRoutes = async () => {
    await generate()
    router.addRoute({
      path: '/',
      name: 'layout',
      component: Layout,
      children: routes.value.concat(testRoutes).concat(processRoutes)
    })
    router.addRoute({
      path: '/:pathMatch(.*)*',
      redirect: { name: '404' }
    })
    if (routes.value.length) {
      setLayoutRouteRedirect({ name: routes.value[0].name })
    } else if (sider.value.length) {
      getFirstSideItem(sider.value)
    }
  }

  const getFirstSideItem = (items: any[]) => {
    if (hrefRedirect.value) return
    for (const e of items) {
      if (e.isDir) {
        getFirstSideItem(e.children)
        continue
      }

      if (e.href) {
        hrefRedirect.value = e.href
        break
      }
    }
  }

  const checkUserInfo = async () => {
    queryconfigINfoData()
    if (userInfo.value) return
    const [error, res] = await sendRequest<HttpResponse<UserModel>>({
      module: 'user',
      api: 'info',
      uri: {
        id: ''
      }
    })

    if (error) throw error
    if (res.code !== 0) throw new Error(res.msg)
    userInfo.value = res.data
  }

  const removeUserInfo = async () => {
    userInfo.value = null
  }

  const setLayoutRouteRedirect = (redirect?: RouteRecordRedirectOption) => {
    const routes = router.getRoutes()
    const layoutRoutes = routes.find((e) => e.name === 'layout')
    if (!layoutRoutes) return
    layoutRoutes.redirect = redirect
  }

  /**更新用户信息 */
  const updateUserInfo = async () => {
    const [error, res] = await sendRequest<HttpResponse<UserModel>>({
      module: 'user',
      api: 'info',
      uri: {
        id: ''
      }
    })

    if (error) throw error
    if (res.code !== 0) throw new Error(res.msg)
    userInfo.value = res.data
    console.log('userInfo.value: ', userInfo.value)
  }

  // 头像
  const queryconfigINfoData = async () => {
    const [error, res] = await sendRequest({
      module: 'selfDesktop',
      api: 'selfDesktopInfo'
    })
    if (error) return
    if (res.code !== 0) return
    headSculpture.value = res.data.headSculpture || defaultAvatar
    console.log('headSculpture.value: ', headSculpture.value);
  }

  return {
    buttonAuth,
    routes,
    hrefRedirect,
    sider,
    permissions,
    userInfo,
    headSculpture,
    setLayoutRouteRedirect,
    removeRoutes,
    addRoutes,
    hasPermission,
    removeUserInfo,
    checkUserInfo,
    stagingFlag,
    updateUserInfo,
    queryconfigINfoData
  }
})

export type Sider = {
  name: string
  label: string
  isDir: boolean
  isExternal: boolean
  href?: string
  icon: string | null
  children?: Sider[]
}

const modules = import.meta.glob(['../views/**/*.vue', '../views/**/*.tsx'], {
  import: 'default',
  eager: false
})
const getView = (filepath: string) => {
  const component = modules[`../views${filepath}`] as any
  return component ? component : modules['../views/Error/NotFound.vue']
}
